﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;

using Atosenet.PluginEngine;


namespace Atosenet.IO
{
    [PluginAttribute("Atosenet", "Atosenet.IO.TcpServerIO", "TCP服务端连接", PluginType.IO)]
    internal class TcpServerIO : BaseIO
    {
        #region 成员

        private Socket _tcpSocket;
        private Thread _tcpThread;
        private IPEndPoint _localEP;

        #endregion


        #region 初始化

        public TcpServerIO()
            : base(TcpServerIOParameter.Default)
        { }

        public TcpServerIO(TcpServerIOParameter param)
            : base(param)
        { }

        #endregion


        #region 公开函数

        public override bool ApplyParameter()
        {
            try
            {
                if (IsOpened)
                    return false;

                _localEP = new IPEndPoint(IPAddress.Any, IOParam.ListeningPort);
                return true;
            }
            catch
            {
                return false;
            }
        }

        public override bool Open()
        {
            try
            {
                if (IsOpened)
                    return false;

                _tcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                _tcpSocket.ReceiveBufferSize = 1024 * 128;
                _tcpSocket.SendBufferSize = 1024 * 128;

                int SIO_KEEPALIVE_VALS = -1744830460; 
                byte[] inValue = new byte[] { 1, 0, 0, 0, 0x20, 0x4E, 0, 0, 0xD0, 0x07, 0, 0 }; //True, KeepAlive时间 20 秒 = 0x4E20, 检查间隔 2 秒 = 0x07D0 
                _tcpSocket.IOControl(SIO_KEEPALIVE_VALS, inValue, null);

                _tcpSocket.Bind(_localEP);
                _tcpSocket.Listen(0x7fffffff);

                if (_tcpThread == null || _tcpThread.ThreadState != System.Threading.ThreadState.Running)
                {
                    _tcpThread = new Thread(new ThreadStart(ListeningProc));
                    _tcpThread.IsBackground = true;
                    _tcpThread.Name = "TcpServerIO_ListeningThread";
                    _tcpThread.Start();
                }

                OnIOOpened();
                return true;
            }
            catch
            {
                if (_tcpThread != null && _tcpThread.IsAlive)
                    _tcpThread.Abort();
                return false;
            }
        }

        public override bool Close()
        {
            try
            {
                if (!IsOpened)
                    return false;

                _tcpSocket.Shutdown(SocketShutdown.Both);
                _tcpSocket.Close(5);
                CloseAllClients();

                if (_tcpThread != null && _tcpThread.IsAlive)
                    _tcpThread.Abort();

                OnIOClosed();
                return true;
            }
            catch
            {
                return false;
            }
        }

        public override bool Close(int id)
        {
            if (id == ID)
                return Close();

            OnIOClosed(id);
            return Clients.Remove(id);
        }

        public override int WriteTo(int id, byte[] buffer, int offset, int length)
        {
            if (id == ID)
                return Write(buffer, offset, length);

            try
            {
                if(!IsOpened)
                    return -1;
                                
                ClientIO cIO = Clients.Find(id);
                return cIO != null ? (cIO.ClientSocket != null ? cIO.ClientSocket.Send(buffer, offset, length, SocketFlags.None) : -1) : -1;
            }
            catch
            {
                return -1;
            }
        }

        public override int Write(byte[] buffer, int offset, int length)
        {
            try
            {
                if (!IsOpened)
                    return -1;

                for (int i = 0; i < Clients.Count; i++)
                {                    
                    if (Clients[i].ClientSocket != null)
                        Clients[i].ClientSocket.Send(buffer, offset, length, SocketFlags.None);
                }
                return Clients.Count * length; 
            }
            catch
            {
                return -1;
            }
        }

        #endregion


        #region 核心函数

        protected virtual void ListeningProc()
        {
            try
            {
                while (true)
                {
                    Socket cSocket = _tcpSocket.Accept();                    
                    ClientIO io = GetClientObject((IPEndPoint)cSocket.RemoteEndPoint, cSocket);                    
                }
            }
            catch
            {
                OnRawDataReceived(IOErrorType.ReadError);
            }
        }

        private ClientIO GetClientObject(IPEndPoint address, Socket skt)
        {
            if (Clients.Contains(address))
            {
                return Clients.Find(address);
            }
            else
            {
                int id = Clients.Add(address, skt);
                OnIOOpened(id);
                return Clients.Find(id);
            }
        }

        private void CloseAllClients()
        {
            for (int i = 0; i < Clients.Count; i++)
            {
                Close(Clients[i].ID);
            }
        }

        #endregion


        #region 属性

        public override IOModeType IOMode
        {
            get { return IOModeType.Server; }
        }

        public new TcpServerIOParameter IOParam
        {
            get { return base.IOParam as TcpServerIOParameter; }
        }

        #endregion


        #region 附加对象



        #endregion
    }
}
